#import "UniqueKey.h"
#import "MasterDetail.h"


static BOOL _Debug = YES;

@implementation MasterDetail

/******************************************************************************
* Create an instance of the UniqueKey object to grab blocks of <count> keys for
* our use during insert.  The count is set low so you can see the SQL reserve
* blocks of keys.  Up the count to something larger for it to be of use.
*
* The login information (connection dictionary) has been blanked out, since
* you may elect to have the tables in some database other than PEOPLE, so we
* elect to run a login panel.  Once the login is complete we can get the
* connection dictionary from the adaptor and use that information to allow
* UniqueKey to login and create its separate connection for key reservation.
*
* Many of the method calls in EOF return (id)<some protocol>, so you will notice
* several casts to (id) to avoid warnings for nested method calls supported by
* the returned object, but not by the protocol.  Alternatively, you can cast to
* the exact class you know returned, such as (EODatabaseDataSource*) or
* (EODetailDatabaseSource*).
******************************************************************************/
- appDidInit:sender
{
    EOAdaptorChannel *eoAdaptorChannel = [[(id)[employeeController dataSource] 
														databaseChannel] adaptorChannel];
    EOAdaptor        *eoAdaptor        = [[eoAdaptorChannel adaptorContext] adaptor];
    
    if(_Debug) [eoAdaptorChannel setDelegate:self];

    employeeEntity       = [[(id)[employeeController dataSource] entity] retain];
    equipmentOwnerEntity = [[(id)[equipmentOwnerController dataSource] entity] retain];

    if(![eoAdaptor runLoginPanelAndValidateConnectionDictionary]) [NXApp terminate:self];
    [UniqueKey setConnectionDictionary:[eoAdaptor connectionDictionary]];
    
    employeeUniqueKey = [[[UniqueKey alloc] initWithEntity:employeeEntity count:5] retain];
    if(!employeeUniqueKey) [NXApp terminate:self];

    [self setFetchOrderFor:employeeController with:@"LastName" order:EOAscendingOrder];
    [self setFetchOrderFor:equipmentOwnerController with:@"Description" order:EOAscendingOrder];

    [employeeController fetch:self];
    return self;
}


/******************************************************************************
* Set a controller's data source to fetch sorted by a given attribute name
* and order.
******************************************************************************/
- setFetchOrderFor:(EOController*)controller with:(NSString*)attributeName order:(EOOrdering)order
{
    id		dataSource = [controller dataSource];
    id		attribute  = [[dataSource entity] attributeNamed:attributeName];
    NSArray	*orderArray;
    
    orderArray = [NSArray arrayWithObject:
    	[EOAttributeOrdering attributeOrderingWithAttribute:attribute ordering:order]];
    [dataSource setFetchOrder:orderArray];
    return self;
}


/******************************************************************************
* Generate unique keys for the new object.  Use the instance of UniqueKey
* to dole out a key from its internal buffer.  The UniqueKey object has its
* own channel to the DB which it uses to allocate blocks of keys.
******************************************************************************/
- (BOOL)controller:(EOController *)controller willInsertObject:object atIndex: (unsigned)newIndex
{
    if(controller==employeeController)
	{
	NSNumber       *uniqueKey  = [NSNumber numberWithInt:[employeeUniqueKey nextKey]];
	NSArray        *emptyArray = [[[NSArray alloc] init] autorelease];

	[object setObject:uniqueKey      forKey:@"EmpId"];
	[object setObject:@"<LastName>"  forKey:@"LastName"];
	[object setObject:@"<FirstName>" forKey:@"FirstName"];
	[object setObject:@"<Phone>"     forKey:@"Phone"];
	[object setObject:emptyArray     forKey:@"toEmpEquipment"];
	return YES;
	}
    return NO;
}


/******************************************************************************
* When an employee is deleted from the database, we need to remove that person's
* ownership of their equipment.  We use the toEmpEquipment relationship to get
* an NSArray of equipment objects and null the EmpId for each.
******************************************************************************/
- (BOOL)controller:controller willDeleteObject:object
{
	NSArray 		*eeArray;
	NSEnumerator	*eeEnumerator;
	EOGenericRecord	*equipment;

    if(controller==employeeController) {
    	eeArray      = [object objectForKey:@"toEmpEquipment"];
		eeEnumerator = [eeArray objectEnumerator];
		
	while ((equipment = [eeEnumerator nextObject]) != nil)  {
		[equipment setObject:[EONull null] forKey:@"EmpId"];
		[(id)[employeeController dataSource] updateObject:equipment];
	}
    }
    return YES;
}


/******************************************************************************
* Bring up the assign equipment panel and start a modal session.  Construct 
* an 'otherEquipment' qualifier to select equipment not currently assigned to
* the selected employee.
******************************************************************************/
- assignEquipmentToEmployee:sender
{
    EOGenericRecord	*employee;
    NSNumber		*empId;
    EOQualifier		*otherEquipment;
    NSString		*qualifierString;
    
	employee = [(id)[equipmentForEmployeeController dataSource] masterObject];
   	empId    = [employee objectForKey:@"EmpId"];

    qualifierString = [NSString stringWithFormat:@"(EmpId != %@ or EmpId = NULL)",empId];
	
    otherEquipment = [[[EOQualifier alloc]
     	initWithEntity:equipmentOwnerEntity qualifierFormat:qualifierString] autorelease];
	
    [(id)[equipmentOwnerController dataSource] setQualifier:otherEquipment];
    [equipmentOwnerController clearSelection];
    [equipmentOwnerController fetch];
    [[assignEquipmentPanel center] makeKeyAndOrderFront:nil];
    [NXApp runModalFor:assignEquipmentPanel];
    [assignEquipmentPanel orderOut:self];
    [employeeController fetch];
    return self;
}

- assignEquipmentToEmployeeOK:sender
{
    EOGenericRecord	*employee;
    NSNumber		*empId;
    NSArray			*eoArray;
    NSEnumerator	*eoEnumerator;
    EOGenericRecord	*equipmentOwner;

	employee		= [(id)[equipmentForEmployeeController dataSource] masterObject];
    empId			= [employee objectForKey:@"EmpId"];
    eoArray			= [equipmentOwnerController selectedObjects];
    eoEnumerator	= [eoArray objectEnumerator];

    while((equipmentOwner = [eoEnumerator nextObject]) != nil) {
	[equipmentOwner setObject:empId forKey:@"EmpId"];
	[(id)[equipmentOwnerController dataSource] updateObject:equipmentOwner];
    }
    [NXApp stopModal];
    return self;
}


/******************************************************************************
* Release the equipment shown in the detail view.  Null out the equipment owner's
* EmpId for each.
******************************************************************************/
- releaseEquipmentForEmployee:sender
{
    NSArray		*efeArray;
    NSEnumerator	*efeEnumerator;
    EOGenericRecord	*equipment;

	efeArray		= [equipmentForEmployeeController selectedObjects];
    efeEnumerator	= [efeArray objectEnumerator];

    while( (equipment = [efeEnumerator nextObject]) != nil) {
	[equipment setObject:[EONull null] forKey:@"EmpId"];
	[(id)[equipmentForEmployeeController dataSource] updateObject:equipment];
    }
    [employeeController fetch];
    return self;
}


/******************************************************************************
* Echo SQL when debug is enabled.
******************************************************************************/
- (EODelegateResponse)adaptorChannel:channel willEvaluateExpression:(NSMutableString *)expression
{
    NSLog(expression);
    return EODelegateApproves;
}

- (void)dealloc
{
	[employeeEntity release];
	[equipmentOwnerEntity release];
	[employeeUniqueKey release];
	[super dealloc];
   
}

@end
